/*
 * ModelCC, distributed under ModelCC Shared Software License, www.modelcc.org
 */

package org.modelcc.language.syntax;

import java.io.Serializable;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;

import org.modelcc.AssociativityType;
import org.modelcc.language.metamodel.LanguageModel;

/**
 * Syntactic constraints.
 * 
 * @author Luis Quesada (lquesada@modelcc.org)
 */
public final class SyntaxConstraints implements Serializable 
{
	/**
	 * Language model
	 */
	private LanguageModel model;

    /**
     * Map of associativities.
     */
    private Map<Object,AssociativityType> associativities;

    /**
     * Map of composition precedences.
     */
    private Map<Rule, Set<Rule>> compositionPrecedences;

    /**
     * Map of selection precedences.
     */
    private Map<Rule, Set<Rule>> selectionPrecedences;

    /**
     * Map of start precedences.
     */
    private Map<Rule, Set<Rule>> startPrecedences;

    /**
     * Constructor.
     */
    public SyntaxConstraints () 
    {
        this.model = null;
        this.associativities = new HashMap<Object,AssociativityType>();
        this.compositionPrecedences = new HashMap<Rule, Set<Rule>>();
        this.selectionPrecedences = new HashMap<Rule, Set<Rule>>();
        this.startPrecedences = new HashMap<Rule, Set<Rule>>();
    }

    // Getters
    
    public LanguageModel getModel ()
    {
    	return model;
    }
    
    
    public Map<Object,AssociativityType> getAssociativities() 
    {
        return Collections.unmodifiableMap(associativities);
    }

    public AssociativityType getAssociativity (Object type)
    {
    	return associativities.get(type);
    }
    
    
    public Map<Rule, Set<Rule>> getCompositionPrecedences() 
    {
        return Collections.unmodifiableMap(compositionPrecedences);
    }
    
    public Set<Rule> getCompositionPrecedences (Rule r)
    {
    	return compositionPrecedences.get(r);
    }
    
    
    public Map<Rule, Set<Rule>> getSelectionPrecedences() 
    {
        return Collections.unmodifiableMap(selectionPrecedences);
    }
    
    public Set<Rule> getSelectionPrecedences (Rule r)
    {
    	return selectionPrecedences.get(r);
    }
    

    public Map<Rule, Set<Rule>> getStartPrecedences() 
    {
        return Collections.unmodifiableMap(startPrecedences);
    }
    
    public Set<Rule> getStartPrecedences (Rule r)
    {
    	return startPrecedences.get(r);
    }
    
    
    // Setters
    
    public void setModel (LanguageModel model)
    {
    	this.model = model;
    }
    
    
    /**
     * Set an associativity constraint for an object type.
     * @param type the object type.
     * @param as the associativity constraint.
     */
    public void setAssociativity (Object type, AssociativityType as) 
    {
        if (as==AssociativityType.UNDEFINED)
            associativities.remove(type);
        else
            associativities.put(type,as);
    }
    
    
    /**
     * Adds a composition precedence between rules.
     * @param ts1 the rule that precedes.
     * @param ts2 the rule that is preceded.
     */
    public void addCompositionPrecedences(Rule ts1,Rule ts2) {
        if (ts1 != null && ts2 != null) {
            Set<Rule> set = compositionPrecedences.get(ts1);
            if (set == null) {
                set = new HashSet<Rule>();
                compositionPrecedences.put(ts1,set);
            }
            set.add(ts2);
        }
    }

    /**
     * Adds a start precedence between rules.
     * @param ts1 the rule that precedes.
     * @param ts2 the rule that is preceded.
     */
    public void addStartPrecedences(Rule ts1,Rule ts2) {
        if (ts1 != null && ts2 != null) {
            Set<Rule> set = startPrecedences.get(ts1);
            if (set == null) {
                set = new HashSet<Rule>();
                startPrecedences.put(ts1,set);
            }
            set.add(ts2);
        }
    }

    /**
     * Removes a composition precedence between rules.
     * @param ts1 the rule that precedes.
     * @param ts2 the rule that is preceded.
     */
    public void removeCompositionPrecedences(Rule ts1,Rule ts2) {
        if (ts1 != null && ts2 != null) {
            Set<Rule> set = compositionPrecedences.get(ts1);
            if (set == null) {
                return;
            }
            set.remove(ts2);
            if (set.isEmpty())
                compositionPrecedences.remove(ts1);
        }
    }


    /**
     * Adds an selection precedence between rules.
     * @param ts1 the rule that precedes.
     * @param ts2 the rule that is preceded.
     */
    public void addSelectionPrecedences(Rule ts1,Rule ts2) {
        if (ts1 != null && ts2 != null) {
            Set<Rule> set = selectionPrecedences.get(ts1);
            if (set == null) {
                set = new HashSet<Rule>();
                selectionPrecedences.put(ts1,set);
            }
            set.add(ts2);
        }
    }

    /**
     * Removes an selection precedence between rules.
     * @param ts1 the rule that precedes.
     * @param ts2 the rule that is preceded.
     */
    public void removeSelectionPrecedences(Rule ts1,Rule ts2) {
        if (ts1 != null && ts2 != null) {
            Set<Rule> set = selectionPrecedences.get(ts1);
            if (set == null) {
                return;
            }
            set.remove(ts2);
            if (set.isEmpty())
                selectionPrecedences.remove(ts1);
        }
    }
    
    
}
